package com.example.com.netty.listen;

import com.example.com.netty.handle.NettyTCPHandler;
import com.example.com.netty.handle.NettyUDPHandler;
import com.example.com.netty.message.MessageDecoder;
import com.example.com.netty.message.MessageEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

/**
 * @author 杜豪波
 * @description: TODO
 * @date 2020/1/3 14:22
 */
public class NettyServerListen {

    private static final Logger logger = LoggerFactory.getLogger(NettyServerListen.class);
    private static final int BIZGROUPSIZE = Runtime.getRuntime().availableProcessors() * 2;
    private static final int BIZTHREADSIZE = 100;
    private static final EventLoopGroup bossGroup = new NioEventLoopGroup(BIZGROUPSIZE);
    private static final EventLoopGroup workerGroup = new NioEventLoopGroup(BIZTHREADSIZE);

    /**
     * @function 初始化 TCP服务
     * @param localIsa 本地服务器地址与端口
     */
    public void initTCP(InetSocketAddress localIsa) {
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup);
            serverBootstrap.channel(NioServerSocketChannel.class);
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);

            serverBootstrap.childHandler(new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    // 服务端设置的超时时间是30秒,客户端设置29秒
                    pipeline.addLast(new IdleStateHandler(30, 0, 0, TimeUnit.SECONDS));
                    pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                    pipeline.addLast(new LengthFieldPrepender(4));
                    pipeline.addLast(new MessageDecoder(1<<20, 10, 4));
                    pipeline.addLast(new MessageEncoder());
                    // 服务端业务逻辑
                    pipeline.addLast("handler", new NettyTCPHandler());
                }
            });
            ChannelFuture channelFuture = serverBootstrap.bind(localIsa).sync();
            logger.debug("开启TCP服务,本地地址  " + localIsa.toString());
            // 监听服务器关闭监听
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("msg", e);
        } finally {
            // 关闭EventLoopGroup，释放掉所有资源包括创建的线程
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            logger.debug("关闭TCP服务,本地地址  " + localIsa.toString());
        }
    }

    /**
     * @function 初始化 UDP服务
     * @param localIsa 本地服务器地址与端口
     */
    public void initUDP(InetSocketAddress localIsa) {
        try {
            // udp不能使用ServerBootstrap
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workerGroup);
            // 设置UDP通道
            bootstrap.channel(NioDatagramChannel.class);
            // 初始化处理器
            bootstrap.handler(new NettyUDPHandler())
                    // 支持广播
                    .option(ChannelOption.SO_BROADCAST, true)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    // 设置UDP读缓冲区为1M
                    .option(ChannelOption.SO_RCVBUF, 1024 * 1024)
                    // 设置UDP写缓冲区为1M
                    .option(ChannelOption.SO_SNDBUF, 1024 * 1024);

            ChannelFuture channelFuture = bootstrap.bind(localIsa).sync();

            logger.debug("开启UDP服务,本地地址  " + localIsa.toString());

            // 监听服务器关闭监听
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("msg", e);
        } finally {
            // 关闭EventLoopGroup，释放掉所有资源包括创建的线程
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            logger.debug("关闭UDP服务,本地地址  " + localIsa.toString());
        }
    }

}
